/*
 * InvertedListSerializer.cpp
 *
 *  Created on: Nov 29, 2012
 *      Author: m
 */

#include "InvertedListSerializer.h"

namespace physical
{

InvertedListSerializer::InvertedListSerializer()
{
}

InvertedListSerializer::~InvertedListSerializer()
{
}

size_t InvertedListSerializer::serialize( const InvertedList& element,
        byteStream block )
{
    invertedListElement_t invertedListSize;
    size_t usedBytes = 0;
    byte* blockPtr = block;

    /*
     * Verifico que el tamaño de la lista invertida a serializar
     *  sea mayor a cero
     */
    if ( element.empty() )
    {
        throw InvalidSizeException();
    }

    /*
     * Primero serializo el tamaño de la lista (como un
     *  invertedListElement_t, aka unsigned short)
     */
    invertedListSize = element.size();
    memcpy( blockPtr, &invertedListSize, sizeof(invertedListElement_t) );

    usedBytes += sizeof(invertedListElement_t);
    blockPtr  += sizeof(invertedListElement_t);

    // Grabo el primer elemento como viene
    memcpy( blockPtr, &element.front(), sizeof(invertedListElement_t) );

    usedBytes += sizeof(invertedListElement_t);
    blockPtr  += sizeof(invertedListElement_t);

    /*
     * Después por cada elemento restante calculo
     *  la distancia al anterior y la serializo
     */
    for ( size_t i = 1; i < element.size(); i++ )
    {
        invertedListElement_t distance = element[i] - element[i - 1];

        memcpy( blockPtr, &distance, sizeof(invertedListElement_t) );

        usedBytes += sizeof(invertedListElement_t);
        blockPtr  += sizeof(invertedListElement_t);
    }

    return usedBytes;
}

size_t InvertedListSerializer::deserialize( const byteStream block,
        InvertedList& element )
{
    invertedListElement_t invertedListSize;
    size_t usedBytes = 0;
    byte* blockPtr = ( byte* ) ( block );

    /*
     * Primero limpio el contenido de la lista invertida
     */
    element.clear();

    /*
     * Luego de-serializo el tamaño de la lista (como un
     *  invertedListElement_t, aka unsigned short)
     */
    memcpy( &invertedListSize, blockPtr, sizeof(invertedListElement_t) );

    usedBytes += sizeof(invertedListElement_t);
    blockPtr  += sizeof(invertedListElement_t);

    // Deserializo el primer elemento de la lista
    element.push_back( *( ( invertedListElement_t * ) ( blockPtr ) ) );

    usedBytes += sizeof(invertedListElement_t);
    blockPtr  += sizeof(invertedListElement_t);

    /*
     * Luego voy re-armando los elementos a partir de su
     *  distancia al anterior y los voy guardando en la lista
     */
    for ( char i = 1; i < invertedListSize; ++i )
    {
        // recupero la distancia
        unsigned short distance = *( ( invertedListElement_t * ) ( blockPtr ) );

        // recupero el valor como la suma de la distancia y el anterior
        element.push_back( element[i - 1] + distance );

        usedBytes += sizeof(invertedListElement_t);
        blockPtr += sizeof(invertedListElement_t);
    }

    return usedBytes;
}

size_t InvertedListSerializer::getSize( const InvertedList& element )
{
    /*
     * Verifico que el tamaño de la lista invertida a serializar
     *  sea mayor a cero
     */
    if ( element.empty() )
    {
        throw InvalidSizeException();
    }

    /*
     * Serializar una lista ocupa 1 byte (para guardar el tamaño)
     * más su cantidad de elementos por sizeof( unsigned short ),
     * que es el tipo con el que se guardan los elementos
     */
    return sizeof(invertedListElement_t) + element.size() * sizeof(invertedListElement_t);
}

} /* namespace physical */
